package org.monster.boot;

import org.monster.context.core.communicator.CommunicatorThreadPool;
import org.monster.context.core.communicator.HttpCommunicator;
import org.monster.context.core.manager.StringManager;

import javax.net.ServerSocketFactory;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 套接字接收器
 * Dos活动 ：{@link SocketReceiverProxy} ---> {@link SocketReceiver}的wirteSocket方法<br>
 * Http活动：http请求 ---> {@link SocketReceiver}
 *
 * @author Monster
 */
public class SocketReceiver extends Thread {

    /**
     * 字符串管理器
     */
    private static final StringManager sm = StringManager.getManager(Constants.Package);
    /**
     * 日志器
     */
    private static final Logger logger = Logger.getLogger(SocketReceiver.class
            .getName());
    /**
     * 通讯器池
     */
    private static final CommunicatorThreadPool COMMUNICATOR_POOL = new CommunicatorThreadPool(10, 20);
    /**
     * 服务器套接字工厂
     */
    private static final ServerSocketFactory ssf = ServerSocketFactory.getDefault();
    /**
     * 侦听端口
     */
    private int port = Constants.PORT;
    /**
     * 停止标识
     */
    private volatile boolean stopped = true;
    /**
     * 服务器{@link ServerSocket}
     */
    private ServerSocket serverSocket;

    /**
     * 写入套接字
     * 提供Dos命名写入Socket的方方法
     *
     * @param dosCommand {@link String}
     * @return {@link String} 返回写入字符流数，可能为零。
     * @throws java.io.IOException
     */
    public int writeSocket(String dosCommand) throws IOException {
        SocketAddress address = new InetSocketAddress(port);
        SocketChannel channel = SocketChannel.open();
        channel.connect(address);
        byte[] bytes = dosCommand.getBytes();
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        return channel.write(buffer);
    }

    /**
     * 运行
     * 开启一个服务器侦听端口线程。 当接收到浏览器发送的请求。在通信器池获取通信器开启服务。
     */
    @Override
    public void run() {
        try {
            serverSocket = ssf.createServerSocket(port);
        } catch (IOException ex) {
            logger.log(Level.SEVERE, sm
                    .getString("socketReceiver.serverSocketCreateEx"));
        }
        logger.log(Level.INFO, sm
                .getString("socketReceiver.portInfo", serverSocket.getLocalPort()));
        while (stopped) {
            Socket socket = null;
            try {
                //接收客户的请求
                socket = serverSocket.accept();
            } catch (IOException ex) {
                logger.log(Level.SEVERE, sm
                        .getString("socketReceiver.serverSocketAcceptEx"));
            }
            try {
                //Http通信器处理Socket对象包含的请求数据
                COMMUNICATOR_POOL.startCommunicatorThread(new HttpCommunicator(socket));
            } catch (InterruptedException ex) {
                logger.log(Level.SEVERE, sm
                        .getString("socketReceiver.communicatorInterruptedEx"));
            }
        }
    }
}
